

function HttpSocket(method, server)
{
    var this_http_socket = this;

    /* public variables */
    this.method = method.toUpperCase();
    this.server = server;
    this.port = 80;
    this.request_headers = new Object();
    this.response_code = 0;
    this.response_headers = new Object();
    this.response_content;
    this.send_byte_arr = null;
    this.progress_callback = function(bytes_written) { air.trace("Wrote "+bytes_written+" bytes");};
    this.error_callback = function(event) { air.trace("Error Event", event); };
    this.complete_callback = function() { air.trace("Transaction complete"); };

    /* protected variables */
    this.sock = new air.Socket();

    /* private variables */
    this.receive_mode = 1; /* 1=header data, 2=content */
    this.header_buffer = '';
    this.bytes_written = 0;

    this.sendHTTPHeader = function ()
    {
        air.trace("Sending HTTP header over socket");
        if (!this.sock.connected) {
            air.trace("Trying to send an HTTP header on un-opened socket");
            return false;
        }
        this.sock.writeUTFBytes(this.method + ' ' + this.path +" HTTP/1.0\r\n");
        this.sock.writeUTFBytes("Host: "+this.server+"\r\n");
        for (var i in this.request_headers) {
            this.sock.writeUTFBytes(i+": "+this.request_headers[i]+"\r\n");
        }
        this.sock.writeUTFBytes("\r\n");
        return true;
    }

    this.sendPayload = function ()
    {
        if (!this.sock.connected) {
            air.trace("Trying to send an HTTP header on un-opened socket");
            return false;
        }
        if (this.send_byte_arr == null) {
            air.trace("Payload content is null");
            return false;
        }
        this.sendSomeBytes(512);
        air.trace("Finished sending payload");
        return true;
    }

    this.sendSomeBytes = function(number_of_bytes)
    {
        var bytes_this_iteration = 0;
        while (this.send_byte_arr.bytesAvailable > 0 && bytes_this_iteration < number_of_bytes) {
            bite = this.send_byte_arr.readByte();
            this.sock.writeByte(bite);
            this.bytes_written++;
            bytes_this_iteration++;
        }
        air.trace("Wrote "+bytes_this_iteration+" bytes, flushing socket");
        this.sock.flush();
        this.progress_callback(this.bytes_written);
        this.bytes_written = 0;

        if (this.send_byte_arr.bytesAvailable > 0) {
            timer = new air.Timer(1, 1);
            timer.addEventListener(air.TimerEvent.TIMER, function(event){ this_http_socket.sendSomeBytes(512); } );
            timer.start();
        }
    }

    this.receiveSocketData = function (event)
    {
        if (this.receive_mode == 1) {
            air.trace("Receiving response header", event.bytesLoaded);
            this.header_buffer += this.sock.readUTFBytes(event.bytesLoaded);
            splits = this.header_buffer.split("\r\n\r\n");
            if (splits.length >= 2) {
                //Get header
                header_lines = splits[0].split("\r\n");
                parts = header_lines[0].split(' ');
                this.response_code = parts[1];
                for (i = 1; i < header_lines.length; i++) {
                    parts = header_lines[i].split(": ");
                    this.response_headers[parts[0]] = parts[1];
                }
                this.header_buffer = splits[0];

                // Get content
                this.response_content = splits[1];
                if (splits.length > 2) {
                    for (i = 2; i < splits.length; i++) {
                        this.response_content += splits[i];
                    }
                }
                this.receive_mode = 2; /* Receive data mode */
            }
        } else {
            air.trace("Receiving response content", event.bytesLoaded);
            this.response_content += this.sock.readUTFBytes(event.bytesLoaded);
        }
    }

    this.socketCommunication = function(event)
    {
        air.trace("Socket connected");
        if (this.sendHTTPHeader()) {
            this.sendPayload();
        }
    }

    this.done = function(event)
    {
        air.trace("Socket closed");
        this.complete_callback();
        if (this.sock.connected) {
            this.sock.close();
        }
    }

    this.talk = function(path)
    {
        this.path = path;
        if (!this.sock.hasEventListener(air.ProgressEvent.SOCKET_DATA)) {
            this.sock.addEventListener(air.ProgressEvent.SOCKET_DATA,
                                       function(event) {
                                            air.trace("Receiving socket data");
                                            this_http_socket.receiveSocketData(event);
                                        });
        } else {
            air.trace("Socket already has a ProgressEvent event listener");
        }
        if (!this.sock.hasEventListener(air.Event.CONNECT)) {
            this.sock.addEventListener(air.Event.CONNECT,
                                       function(event) {
                                            air.trace("Socket connected event");
                                            this_http_socket.socketCommunication(event);
                                        });
        } else {
            air.trace("Socket already has a Connect Event")
        }
        if (!this.sock.hasEventListener(air.Event.CLOSE)) {
            this.sock.addEventListener(air.Event.CLOSE,
                                       function(event) {
                                            air.trace("Socket closed event");
                                            this_http_socket.done(event);
                                        });
        }
        if (!this.sock.hasEventListener(air.IOErrorEvent.IO_ERROR)) {
            this.sock.addEventListener(air.IOErrorEvent.IO_ERROR,
                                       function(event) {
                                            air.trace("Socket io error event");
                                            this_http_socket.error_callback(event);
                                        });
        }
        if (!this.sock.hasEventListener(air.SecurityErrorEvent)) {
            this.sock.addEventListener(air.SecurityErrorEvent.SECURITY_ERROR,
                                       function(event) {
                                            air.trace("Socket security error event");
                                            this_http_socket.error_callback(event);
                                        });
        }
        this.sock.connect(this.server, this.port);
    }
}

function SecureHttpSocket(method, server)
{
    var that = new HttpSocket(method, server);
    that.port = 443;
    that.sock = new air.SecureSocket();
    return that;
}
